package cheme.ProcessEditor.Table;

import java.util.List;

import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.ToolbarLayout;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;

import cheme.ProcessEditor.Parts.Streams.Tag.TableRowData;

public class TableRowLayout extends ToolbarLayout implements ITableElementLayout
{
	private TableRowData actualRowData = null; //this copy will remain unchanged as a reference for shrinking the row
	private TableRowData adjustedRowData = null; //this one may grow to reflect the overall table column sizes
	
	private TableLayout parentLayout;
	private int spacing = 1;
	
	private ITableLayout parent;
	
	public TableRowLayout(TableLayout parentLayout)
	{
		super();
		setVertical(false);
		this.parentLayout = parentLayout;
	}
	
	public ITableLayout getParent()
	{
		return parent;
	}
	public void setParent(ITableLayout parent)
	{
		this.parent = parent;
	}
	
	public int getSpacing()
	{
		return spacing;
	}
	
	public void setSpacing(int spacing)
	{
		this.spacing = spacing;
	}
	
	public TableRowData getAdjustedRowData()
	{
		return adjustedRowData;
	}
	
	public TableRowData getActualRowData()
	{
		return actualRowData;
	}
	
	public void setAdjustedRowData(TableRowData rowData)
	{
		this.adjustedRowData = rowData;
	}
	
	public void setActualRowData(TableRowData rowData)
	{
		this.actualRowData = rowData;
	}
	
//	public void resetRowData()
//	{
//		setRowData(actualRowData);
//	}
	
//	@Override
//	public void invalidate()
//	{
//		System.out.println("----------------------------------");
//		System.out.println("TableRowLayout.invalidate -- start");
//		super.invalidate();
//		System.out.println("TableRowLayout.invalidate -- end");
//	}
//	
//	@Override
//	protected void invalidate(IFigure child)
//	{
//		System.out.println("TableRowLayout.invalidate(IFigure) -- start");
//		super.invalidate(child);
//		System.out.println("TableRowLayout.invalidate(IFigure) -- end");
//	}
	
	private Dimension calculateChildrenSize(List children, int wHint, int hHint, boolean preferred)
	{
//		System.out.println("TableRowLayout.calculateChildrenSize -- start");
		
		Dimension childSize;
		IFigure child = null;
		int height = 0, width = 0;
		
		TableRowData rowData = new TableRowData();
		
		for (int i = 0; i < children.size(); i++)
		{
			child = (IFigure)children.get(i);
			
			childSize = transposer.t(preferred ? child.getPreferredSize(wHint, hHint) : child.getMinimumSize(wHint, hHint));
//			childSize = transposer.t(child.getPreferredSize(wHint, hHint));
			
			if(preferred)
			{
				rowData.spans.add(new ColumnSpan(childSize.height));
			}
			
			height += childSize.height;
			width = Math.max(width, childSize.width);
		}
		
		if(preferred)
		{
			/*
			 * Cache the original data
			 */

			setActualRowData(rowData); //this copy will remain unchanged as a reference for shrinking the row
			setAdjustedRowData(rowData); //this one may grow to reflect the overall table column sizes
			
			parentLayout.updateMaxRowData(this);
		}
		
		//oops, missed this... is it really needed now?
		height = parentLayout.getRowData().totalWidth();
		
//		System.out.println("TableRowLayout.calculateChildrenSize -- end");
		
		return new Dimension(width, height);
	}
	
	@Override
	protected Dimension calculateMinimumSize(IFigure container, int wHint, int hHint)
	{
//		System.out.println("TableRowLayout.calculateMinimumSize -- start");
		
		Insets insets = container.getInsets();
		List children = container.getChildren();
		Dimension minSize = calculateChildrenSize(children, SWT.DEFAULT, SWT.DEFAULT, false); //ignores hints -- :P

		minSize.height += Math.max(0, children.size() - 1) * spacing;
		
//		System.out.println("TableRowLayout.calculateMinimumSize -- end");
		
		return transposer.t(minSize).expand(insets.getWidth(), insets.getHeight()).union(getBorderPreferredSize(container));
	}
	
	@Override
	protected Dimension calculatePreferredSize(IFigure container, int wHint, int hHint)
	{
//		System.out.println("TableRowLayout.calculatePreferredSize -- start");
				
		Insets insets = container.getInsets();
		List children = container.getChildren();
		Dimension prefSize = calculateChildrenSize(children, SWT.DEFAULT, SWT.DEFAULT, true); //ignores hints -- :P
		
		prefSize.height += Math.max(0, children.size() - 1) * spacing;

//		System.out.println("TableRowLayout.calculatePreferredSize -- end");
		
		return transposer.t(prefSize).expand(insets.getWidth(), insets.getHeight()).union(getBorderPreferredSize(container));
	}
	
	@Override
	public void layout(IFigure parent)
	{
//		System.out.println("TableRowLayout.layout -- start");
		
		List children = parent.getChildren();
		int numChildren = children.size();
		Rectangle clientArea = transposer.t(parent.getClientArea());
		int x = clientArea.x;
		int y = clientArea.y;
		int availableHeight = clientArea.height;

		Dimension prefSizes [] = new Dimension[numChildren];
		Dimension minSizes [] = new Dimension[numChildren];
		
		// Calculate the width and height hints.  If it's a vertical ToolBarLayout,
		// then ignore the height hint (set it to -1); otherwise, ignore the 
		// width hint.  These hints will be passed to the children of the parent
		// figure when getting their preferred size. 
		
		int wHint = -1;
		int hHint = -1;    
		
		if (isHorizontal())
		{
			hHint = parent.getClientArea(Rectangle.SINGLETON).height;
		}
		else
		{
			wHint = parent.getClientArea(Rectangle.SINGLETON).width;
		}

		/*		
		 * Calculate sum of preferred heights of all children(totalHeight). 
		 * Calculate sum of minimum heights of all children(minHeight).
		 * Cache Preferred Sizes and Minimum Sizes of all children.
		 *
		 * totalHeight is the sum of the preferred heights of all children
		 * totalMinHeight is the sum of the minimum heights of all children
		 * prefMinSumHeight is the sum of the difference between all children's
		 * preferred heights and minimum heights. (This is used as a ratio to 
		 * calculate how much each child will shrink). 
		 */
		
		IFigure child; 
		int totalHeight = 0;
		int totalMinHeight = 0;
		int prefMinSumHeight = 0;

		for (int i = 0; i < numChildren; i++)
		{
			child = (IFigure)children.get(i);
			
			prefSizes[i] = transposer.t(child.getPreferredSize(wHint, hHint));
			minSizes[i] = transposer.t(child.getMinimumSize(wHint, hHint));
			
			totalHeight += prefSizes[i].height;
			totalMinHeight += minSizes[i].height;
		}
		
		totalHeight += (numChildren - 1) * spacing;
		totalMinHeight += (numChildren - 1) * spacing;
		prefMinSumHeight = totalHeight - totalMinHeight;
	    /* 
		 * The total amount that the children must be shrunk is the 
		 * sum of the preferred Heights of the children minus  
		 * Max(the available area and the sum of the minimum heights of the children).
		 *
		 * amntShrinkHeight is the combined amount that the children must shrink
		 * amntShrinkCurrentHeight is the amount each child will shrink respectively  
		 */	
		int amntShrinkHeight = totalHeight - Math.max(availableHeight, totalMinHeight);

		if (amntShrinkHeight < 0) {
			amntShrinkHeight = 0;
		}

		for (int i = 0; i < numChildren; i++) {
			int amntShrinkCurrentHeight = 0;
			int prefHeight = prefSizes[i].height;
			int minHeight = minSizes[i].height;
			int prefWidth = prefSizes[i].width;
			int minWidth = minSizes[i].width;
			Rectangle newBounds = new Rectangle(x, y, prefWidth, prefHeight);

			child = (IFigure)children.get(i);
		    if (prefMinSumHeight != 0)
				amntShrinkCurrentHeight = 
						(prefHeight - minHeight) * amntShrinkHeight / (prefMinSumHeight);

		    int width = Math.min(prefWidth, transposer.t(child.getMaximumSize()).width);
			if (matchWidth)
				width = transposer.t(child.getMaximumSize()).width;
			width = Math.max(minWidth, Math.min(clientArea.width, width));
			newBounds.width = width;

		    
		    int adjust = clientArea.width - width;
			switch (minorAlignment) {
			case ALIGN_TOPLEFT: 
				adjust = 0;
				break;
			case ALIGN_CENTER:
				adjust /= 2;
				break;
			case ALIGN_BOTTOMRIGHT:
				break;
			}
			newBounds.x += adjust;
			
			//newBounds.height -= amntShrinkCurrentHeight;
			newBounds.height = parentLayout.getRowData().spans.get(i).width;
			
			child.setBounds(transposer.t(newBounds));

			amntShrinkHeight -= amntShrinkCurrentHeight;
			prefMinSumHeight -= (prefHeight - minHeight);
			y += newBounds.height + spacing;
		}
		
//		System.out.println("TableRowLayout.layout -- end");
	}
}
